#pragma once

#include <condition_variable>
#include <mutex>
#include <queue>
#include <stdexcept>

/**
 * 多线程安全队列：
 *  - push()：生产者推送任务，若队列已关闭会抛出异常
 *  - pop()：消费者阻塞式取任务；当队列关闭且为空时返回 false
 *  - close()：标记队列不再接受新任务，并唤醒所有等待线程
 */
template <typename T>
class ThreadSafeQueue {
public:
    ThreadSafeQueue() = default;

    // 禁止拷贝，允许移动
    ThreadSafeQueue(const ThreadSafeQueue&) = delete;
    ThreadSafeQueue& operator=(const ThreadSafeQueue&) = delete;

    ThreadSafeQueue(ThreadSafeQueue&&) = delete;
    ThreadSafeQueue& operator=(ThreadSafeQueue&&) = delete;

    /**
     * 向队列推送一个元素。
     * @throws std::runtime_error 若队列已关闭。
     */
    void push(T value) {
        {
            std::lock_guard<std::mutex> lock(mutex_);
            if (closed_) {
                throw std::runtime_error("push on closed ThreadSafeQueue");
            }
            queue_.push(std::move(value));
        }
        // 推入新任务，只需唤醒一个等待的消费者即可
        cond_.notify_one();
    }

    /**
     * 从队列中弹出一个元素。
     * @param out 用于接收弹出的元素。
     * @return true  => 成功获取一个元素
     *         false => 队列关闭且已空，意味着可以退出消费循环
     */
    bool pop(T& out) {
        std::unique_lock<std::mutex> lock(mutex_);
        cond_.wait(lock, [this] { return !queue_.empty() || closed_; });

        if (queue_.empty()) {
            return false;  // 队列关闭且已无元素
        }

        out = std::move(queue_.front());
        queue_.pop();
        return true;
    }

    /**
     * 关闭队列：禁止再 push，并唤醒所有等待线程以便它们检查 closed 状态。
     */
    void close() {
        {
            std::lock_guard<std::mutex> lock(mutex_);
            closed_ = true;
        }
        cond_.notify_all();
    }

    bool is_closed() const {
        std::lock_guard<std::mutex> lock(mutex_);
        return closed_;
    }

    std::size_t size() const {
        std::lock_guard<std::mutex> lock(mutex_);
        return queue_.size();
    }

private:
    mutable std::mutex mutex_;
    std::condition_variable cond_;
    std::queue<T> queue_;
    bool closed_{false};
};